﻿namespace Proto.Providers
{
    using Proto.Fields;

    public class QuickKey : IKey
    {
        private readonly FieldSet m_Keys;
        private readonly IFieldGetter m_Data;
        private readonly int m_HashCode;
        private readonly object m_Value;
        private readonly FieldID m_FieldID;

        private readonly object[] data;
        public QuickKey( FieldSet keys, IFieldGetter getter )
        {
            m_Keys = keys;
            this.m_Data = getter;
            int count = 0;
            unchecked
            {
                foreach( FieldID field in keys.Fields )
                {
                    count++;
                    m_HashCode = (m_HashCode * 397) ^ getter.Get(field).GetHashCode();
                }
            }
            data = new object[count];
            count = 0;
            
            foreach( FieldID field in keys.Fields )
            {
                data[count++] = getter.Get(field);
            }
        }

        public QuickKey( FieldID id, object value )
        {
            m_FieldID = id;
            m_Value = value;
            m_HashCode ^= m_Value.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if( obj is QuickKey )
            {
                return Equals( (QuickKey)obj );
            }

            if( obj is IFieldGetter )
            {
                return Equals( ((IFieldGetter) obj ).Key );
            }
            return false;
        }

        private bool Equals( QuickKey rhs )
        {
            if (m_Value != null)
            {
                return m_Value.Equals(rhs.m_Value);
            }
            if (rhs.m_HashCode != m_HashCode) return false;
            for (int i = 0; i < data.Length; i++)
                if (data[i].Equals(rhs.data[i]) == false) return false;
            return true;
        }

        private bool Equals( IFieldGetter rhs )
        {
            if( m_Value != null )
            {
                return m_Value.Equals( rhs.Get( m_FieldID ) );
            }
            foreach( FieldID field in m_Keys.Fields )
            {
                if( m_Data.Get( field ).Equals( rhs.Get( field ) ) == false ) return false;
            }
            return true;
        }

        public override int  GetHashCode()
        {
            return m_HashCode;
        }
    }
}